package com.edu.system.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.edu.common.exception.ServiceException;
import com.edu.common.utils.poi.ExcelReaderUtil;
import com.edu.system.domain.ExamDetail;
import com.edu.system.domain.Student;
import com.edu.system.domain.TClassroom;
import com.edu.system.domain.TExamMiss;
import com.edu.system.domain.TExamination;
import com.edu.system.domain.dto.ExamSeatDTO;
import com.edu.system.domain.dto.ExamSeatDTO.SeatItem;
import com.edu.system.mapper.ExamDetailMapper;
import com.edu.system.service.IStudentService;
import com.edu.system.service.ITClassService;
import com.edu.system.service.ITClassroomService;
import com.edu.system.service.ITExamMissService;
import com.edu.system.service.ITExaminationService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import com.edu.system.mapper.TExamSeatMapper;
import com.edu.system.domain.TExamSeat;
import com.edu.system.service.ITExamSeatService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 座位图Service业务层处理
 * 
 * @author xxxx
 * @date 2023-12-31
 */
@Slf4j
@Service
public class TExamSeatServiceImpl implements ITExamSeatService 
{
    @Resource
    private TExamSeatMapper tExamSeatMapper;
    @Resource
    private ITClassService itClassService;
    @Resource
    private ExamDetailMapper examDetailMapper;
    @Resource
    private IStudentService iStudentService;
    @Resource
    private ITExaminationService itExaminationService;
    @Resource
    private ITExamSeatService itExamSeatService;
    @Resource
    private ITExamMissService itExamMissService;
    @Resource
    private ITClassroomService itClassroomService;

    private static final List<String> HEAD_KEYWORDS = Arrays.asList("门", "大门", "讲台", "窗", "窗户", "窗口", "中间");

    private static final Integer STATUS_UP = 1;
    private static final Integer PUBLISH_STATUS_ON = 1;
    /**
     * 查询座位图
     * 
     * @param id 座位图主键
     * @return 座位图
     */
    @Override
    public TExamSeat selectTExamSeatById(Long id)
    {
        TExamSeat seat = tExamSeatMapper.selectTExamSeatById(id);
        if (StrUtil.isNotBlank(seat.getExamSeat())){
            seat.setExamSeatEntity(JSONObject.parseObject(seat.getExamSeat(), ExamSeatDTO.class));
        }

        return seat;
    }

    /**
     * 查询座位图列表
     * 
     * @param tExamSeat 座位图
     * @return 座位图
     */
    @Override
    public List<TExamSeat> selectTExamSeatList(TExamSeat tExamSeat)
    {
        return tExamSeatMapper.selectTExamSeatList(tExamSeat);
    }

    @Override
    public List<TExamSeat> liveExamSeatList(TExamSeat tExamSeat) {
        return tExamSeatMapper.liveList(tExamSeat);
    }

    @Override
    public List<TExamSeat> showExamSeatList(TExamSeat tExamSeat) {
        List<TExamSeat> es = tExamSeatMapper.selectTExamSeatList(tExamSeat);

        Map<Long, TClassroom> roomMap = itClassroomService.selectClassroomMap(
            es.stream().map(TExamSeat::getClassId).collect(Collectors.toList()));

        for (TExamSeat seat : es){
            seat.setClassName(roomMap.getOrDefault(seat.getClassId(), new TClassroom()).getName());
        }
        return es;
    }

    /**
     * 新增座位图
     * 
     * @param seat 座位图
     * @return 结果
     */
    @Override
    @Transactional
    public int insertTExamSeat(TExamSeat seat)
    {
        log.info("座位图fileUrl:{}", seat.getFileUrl());

        Map<String, List<List<String>>> roomSeatMap = ExcelReaderUtil.readExcelFromUrl(seat.getFileUrl());
        Map<String, Long> roomNameMap = new HashMap<>();
        // 校验：判断是否重复添加 考试+教室+学科
        roomSeatMap.forEach((k, v)->{
            // 教室是否存在
            TClassroom classroom = this.checkRoomIsExist(k);
            if (null == classroom){
                throw new ServiceException(String.format("sheet名称: %s，未找到对应的教室", k));
            }
            roomNameMap.put(k, classroom.getId());
            TExamSeat s = new TExamSeat();
            s.setExamId(seat.getExamId());
            s.setClassId(classroom.getId());
            s.setLessonName(seat.getLessonName());
            List<TExamSeat> seats = tExamSeatMapper.selectTExamSeatList(s);
            if (CollectionUtils.isNotEmpty(seats)){
                throw new ServiceException(String.format("教室：%s 已存在 %s 座位图", k, seat.getLessonName()));
            }
        });

        roomSeatMap.forEach((k,v)->{
            seat.setClassId(roomNameMap.get(k));
            int i = tExamSeatMapper.insertTExamSeat(seat);
            this.updateTExamSeat(seat, v);
        });

        return 1;
    }

    private TClassroom checkRoomIsExist(String k) {
        TClassroom r = new TClassroom();
        r.setName(k);
        return Optional.ofNullable(itClassroomService.selectTClassroomList(r))
            .filter(CollectionUtils::isNotEmpty)
            .map(a -> a.get(0))
            .orElseGet(() -> null);
    }

    /**
     * 构建座位矩阵
     *
     * @param
     * @return
     */
    private ExamSeatDTO buildExamSeat(List<List<String>> lists, Long examSeatId) {

        long count = lists.get(0).stream().filter(HEAD_KEYWORDS::contains).count();
        List<String> headers = null;
        if (count >= 2){
            List<String> h = lists.get(0).stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());
            headers = JSONArray.parseArray(JSONArray.toJSONString(h), String.class);
        }

        // 张三（高一3班）=> 张三
        Map<String, String> nameClassMap = new HashMap<>();
        lists.remove(0);

        // 规范括号
        List<List<String>> origData = lists.stream().map(a ->
            a.stream()
                .map(s -> s == null ? "" : s)
                .map(s -> s.replace("（", "("))
                .map(s -> s.replace("）", ")"))
                .collect(Collectors.toList())
        ).collect(Collectors.toList());

        // 所有的姓名（去除班级）
        List<String> names = origData.stream()
            .flatMap(a -> a.stream()
                .filter(StrUtil::isNotBlank)
                .map(s -> {
                    if (s.contains("(")){
                        nameClassMap.put(s, s.substring(0, s.indexOf('(')));
                        return s.substring(0, s.indexOf('('));
                    }
                    return s;
                })
            ).collect(Collectors.toList());

        List<Student> students = iStudentService.queryListByNames(names);
        Map<String, Long> uniqNameIdMap = students
            .stream()
            .peek(a -> {
                if (nameClassMap.containsKey(getNameClass(a))){
                    a.setName(getNameClass(a));
                }
            })
//            .filter(a ->!nameClassMap.containsValue(a.getName()))
            .collect(Collectors.toMap(Student::getName, Student::getId, (x, y) -> x));

        // 检查姓名是否存在 或 重名
        List<String> origNames = origData.stream().flatMap(a -> a.stream().filter(StrUtil::isNotBlank)).collect(Collectors.toList());
        List<String> existNames = new ArrayList<>(uniqNameIdMap.keySet());

        // 检查是否存在重复出现的姓名
        List<String> duplicates = getDuplicate(origNames);
        if (CollectionUtils.isNotEmpty(duplicates)){
            throw new ServiceException(String.format("重名: %s ，重名的后边需带上：（班级名称）", String.join(",", duplicates)));
        }
        origNames.removeAll(existNames);
        if (CollectionUtils.isNotEmpty(origNames)){
            throw new ServiceException("未能匹配到学生：" + StrUtil.join(",", origNames));
        }

        List<List<SeatItem>> itemsArr = origData.stream()
            .map(a -> a.stream().map(b -> buildSeatItem(b, uniqNameIdMap)).collect(Collectors.toList()))
            .collect(Collectors.toList());
        // 防止修改时 不传title
        TExamSeat seat = this.selectTExamSeatById(examSeatId);
        return ExamSeatDTO.builder().header(headers).seatItems(itemsArr).id(examSeatId).examTitle(seat.getTitle()).build();
    }

    private List<String> getDuplicate(List<String> origNames) {
        return origNames.stream()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
            .entrySet().stream()
            .filter(entry -> entry.getValue() > 1)
            .map(Map.Entry::getKey)
            .collect(Collectors.toList());
    }

    private String getNameClass(Student a) {
        return a.getName() + "(" + a.getClassName() + ")";
    }

    private SeatItem buildSeatItem(String name, Map<String, Long> nameIdMap){
        if (!nameIdMap.containsKey(name)){
            return SeatItem.builder().build();
        }
        return SeatItem.builder()
            .id(nameIdMap.get(name))
            .name(name)
            .isMissExam(0)
            .build();
    }

    /**
     * 修改座位图
     * 
     * @param tExamSeat 座位图
     * @return 结果
     */
    @Override
    @Transactional
    public int updateTExamSeat(TExamSeat tExamSeat, List<List<String>> lists)
    {
        // 处理座位图excel
        if (lists != null){
            ExamSeatDTO build = buildExamSeat(lists, tExamSeat.getId());
            tExamSeat.setExamSeat(JSONArray.toJSONString(build));

            // 参考学生明细
            TExamination exam = itExaminationService.selectTExaminationById(tExamSeat.getExamId());
            List<ExamDetail> details = new ArrayList<>();
            build.getSeatItems().forEach(a -> {
                a.stream()
                    .filter(b->b.getId() != null)
                    .forEach(b -> {
                    details.add(ExamDetail.builder()
                        .cohort(exam.getCohort())
                        .examId(tExamSeat.getExamId())
                        .seatId(tExamSeat.getId())
                        .studentId(b.getId())
                        .lessonName(tExamSeat.getLessonName())
                        .build());
                });
            });
            examDetailMapper.deleteBySeatId(tExamSeat.getId());
            examDetailMapper.batchInsert(details);
        }

        return tExamSeatMapper.updateTExamSeat(tExamSeat);
    }

    @Override
    public int publishStatusToOn(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)){
            return 0;
        }
        TExamSeat seat = new TExamSeat();
        seat.setPublishStatus(PUBLISH_STATUS_ON);
        seat.setPublishTime(new Date());
        return tExamSeatMapper.publishByIds(ids, seat);
    }

    @Override
    public int editMissExam(Long examSeatId, List<Long> missIds){
        TExamSeat seat = itExamSeatService.selectTExamSeatById(examSeatId);
        ExamSeatDTO examSeatVO = JSONObject.parseObject(seat.getExamSeat(), ExamSeatDTO.class);

        examSeatVO.getSeatItems().forEach(row -> {
            row.forEach(i -> {
                if (missIds.contains(i.getId())){
                    i.setIsMissExam(1);
                } else {
                    i.setIsMissExam(0);
                }
            });
        });

        // 记录到详细表
        TExamination tExamination = itExaminationService.selectTExaminationById(seat.getExamId());
        missIds.forEach(id -> {
            TExamMiss m = new TExamMiss();
            m.setExamId(seat.getExamId());
            m.setExamTitle(tExamination.getTitle());
            m.setExamDate(new Date());
            m.setStudentId(id);
            Student student = iStudentService.selectStudentById(id);
            m.setName(student.getName());
            m.setClassName(student.getClassName());
            m.setClassId(student.getClassId());
            m.setCohort(student.getGeneration());
            m.setLessonName(seat.getLessonName());
            itExamMissService.insertTExamMiss(m);
        });

        TExamSeat update = new TExamSeat();
        update.setId(examSeatId);
        update.setExamSeat(JSONObject.toJSONString(examSeatVO));
        return itExamSeatService.updateTExamSeat(update, null);
    }

    /**
     * 批量删除座位图
     * 
     * @param ids 需要删除的座位图主键
     * @return 结果
     */
    @Override
    public int deleteTExamSeatByIds(Long[] ids)
    {
        return tExamSeatMapper.deleteTExamSeatByIds(ids);
    }

    /**
     * 删除座位图信息
     * 
     * @param id 座位图主键
     * @return 结果
     */
    @Override
    public int deleteTExamSeatById(Long id)
    {
        return tExamSeatMapper.deleteTExamSeatById(id);
    }

    @Override
    public List<Long> queryClassIdsByIds(List<Long> ids) {
        return tExamSeatMapper.selectByIds(ids)
            .stream()
            .map(TExamSeat::getClassId)
            .collect(Collectors.toList());
    }

    @Override
    public List<TExamSeat> queryTodayChangeList() {
        Date date = new Date();
        DateTime beginTime = DateUtil.beginOfDay(date);
        DateTime endTime = DateUtil.endOfDay(date);
        return tExamSeatMapper.needStatusChangeList(beginTime, endTime);
    }
}
